<?php
defined('IN_CMS') or die('Direct access to Script restricted.');

class Functions extends Common
{
	/**
	 * Конструктор класса
	 */
	public function __construct()
	{
		
	}

	/**
	 * Деструктор класса
	 */
	public function __destruct()
	{

	}
	
	/**
	 * 
	 * @param	string	$name
	 */
	public function getSQL($name, $parameters)
	{
		$sql = @file_get_contents(ABSPATH . 'includes/sql/' . $name . '.sql');
		if ($sql === false)
		{
			// Если файл не найден - вернем пустую строку
			$sql = '';
		}
		else 
		{
			// Заменяем параметры в запросе
			foreach($parameters as $key => $value) 
			{
				$sql = str_replace('@' . $key, $value, $sql);
			}
		}
		unset($name, $parameters, $key, $value);
		return $sql;
	}

	/**
	 * Возвращает полученное значение в одинарных кавычках, если это текст,
	 * и без кавычек, если это число.
	 * Используется для подготовки параметра запроса к БД MySQL
	 *
	 * @param	string	$value
	 * @param	bool	$quotes
	 * @return	string
	 */
	public function toMySQL($value, $quotes = false)
	{
		// если magic_quotes_gpc включена - используем stripslashes
		if ( get_magic_quotes_gpc() )
		{
			$value = stripslashes($value);
		}
		if ($quotes)
		{
			// Если $quotes, то принудительно экранируем и закавычиваем
			$value = "'" . mysql_real_escape_string($value) . "'";
		}
		else
		{
			// Если переменная - число, то экранировать её не нужно
			// если нет - то окружем её кавычками, и экранируем
			if ( !is_numeric($value) || substr($value,0,1) == '0' )
			{
				$value = "'" . mysql_real_escape_string($value) . "'";
			}
		}
		unset($quotes);
		return $value;
	}
	
	/**
	 * Перевод тегов в сущности
	 *
	 * @param	string	$text
	 * @return	string
	 */
	public function HTMLtoSPEC($text)
	{
		//$text = htmlentities($text, ENT_QUOTES, 'UTF-8');
		//$text = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
		//$text= $this->toMySQL($text);
		return $text;
	}
	
	/**
	 * Перевод сущностей  в теги
	 *
	 * @param	string	$text
	 * @return	string
	 */
	public function SPECtoHTML($text)
	{
		
		//$text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
		// $text = htmlspecialchars_decode($text, ENT_QUOTES, 'UTF-8');
		//$text = nl2br($text);
		//$text= $this->toHTML($text);
		return $text;
	}
	
	/**
	 * Подготовка сообщения к выводу на экран (в HTML формате)
	 *
	 * @param	string	$text
	 * @return	string
	 */
	public function toHTML($text)
	{
		$text = html_entity_decode($text, ENT_QUOTES);
		$text = htmlspecialchars($text, ENT_QUOTES);
		$text = nl2br($text);
		return $text;
	}

	/**
	 * utf8_strlen()
	 *
	 * @param	string	$s
	 * @return	int
	 */
	public function utf8_strlen($s)
	{
		return preg_match_all('/./u', $s, $tmp);
	}

	/**
	 * utf8_substr()
	 *
	 * @param	string	$s
	 * @param	int		$offset
	 * @param	int		$len
	 * @return 	string
	 */
	public function utf8_substr($s, $offset, $len = 'all')
	{
		if ($offset<0) $offset = $this->utf8_strlen($s) + $offset;
		if ($len!='all')
		{
			if ($len<0) $len = $this->utf8_strlen($s) - $offset + $len;
			$xlen = $this->utf8_strlen($s) - $offset;
			$len = ($len>$xlen) ? $xlen : $len;
			preg_match('/^.{' . $offset . '}(.{0,'.$len.'})/us', $s, $tmp);
		}
		else
		{
			preg_match('/^.{' . $offset . '}(.*)/us', $s, $tmp);
		}

		unset($s, $offset, $len, $xlen);
		return (isset($tmp[1])) ? $tmp[1] : false;
	}

	/**
	 * Усиленный способ вычислении двойного MD5-хэша от текста
	 * Используется для формирования паролей ,сохраняемых в базе данных
	 *
	 * Пример строки "соли", используемой для шифрования
	 * $salt="123!#&%asgfHTA";
	 *
	 * @param 	string	$username
	 * @param	string	$pass
	 * @param	string	$salt
	 *
	 * @return	string
	 */
	public function super_crypt($username, $pass, $salt)
	{
		// Первым делом стоит объявить массив спецсимволов, которые будет участвовать при работе метода замены:
		$spec = array('~','!','@','#','$','%','^','&','*','?');

		// Далее мы получим уже описанную выше хэш-сумму от стандартного метода соления (md5(md5(pass).md5(salt))):
		$crypted = md5(md5($salt).md5($username).md5($pass));

		// Объявим еще одну переменную, в которой будет храниться хэш от несоленого пароля:
		$c_text = md5($pass);

		// Следующим шагом будет составление таблицы соответствия хэш-суммы от соления и хэш-суммы от не-соления.
		$cnt = strlen($crypted);
		for ( $i=0; $i<$cnt; $i++ )
		{
			if ( ord($c_text[$i]) >= 48 && ord($c_text[$i]) <= 57 )
			{
				// Если n’ый символ в MD5-хэше от plain-текста (нешифрованного текста) является цифрой,
				// то в соленом хэше он поменяется на спецсимвол, номер которого в ранее объявленном массиве соответствует этой цифре.
				// То есть второй символ в plain-строке - нуль.
				// Следовательно, он заменит символ «6» в соленой строке символом «~».
				@$temp .= $spec[$c_text[$i]];
			}
			elseif ( ord($c_text[$i]) >= 97 && ord($c_text[$i]) <= 100 )
			{
				// Если n’ый символ в MD5-хэше от plain-текста является буквой и попадает в диапазон a-d,
				// то в соленой строке он переводится в верхний регистр
				@$temp .= strtoupper($crypted[$i]);
			}
			else
			{
				// Ну и если ни одно из условий не выполняется,
				// то в соленой строке он поменяется на символ с соответствующим порядковым
				// номером из строки md5(md5(pass).md5(salt)).
				@$temp .= $crypted[$i];
			}
		}

		// Соберем мусор
		unset($username, $pass, $salt, $spec, $crypted, $c_text, $cnt, $i);

		// После использования этого усиленного метода простенький пароль "proba"
		// превращается в зверя «E~1*c!f%0#~&C3%9##*!?2#*&1%3~!21».
		// А чтобы такой зверь не отличался от остальных своих MD5-братьев, перед выводом на экран,
		// записью в базу или же сравнением переводим его снова в MD5-хэш.
		// Шанс подбора такого пароля снижается практически до нуля.
		return md5($temp);
	}

	/**
	 * Запись кэш-файла
	 * 
	 * @param	string	$content		Содержание буфера
	 * @param	string	$filename		Имя файла, используемое при создании кэш-файла
	 * @return	void
	 */
	public function writeCache($content, $filename)
	{
		$fp = fopen(ABSPATH . 'templates/' . TPL_NAME . '/' . LANG . '/cache/' . $filename, 'w');
		flock($fp, LOCK_EX);
		fputs($fp, $content);
		fflush($fp);
		flock($fp, LOCK_UN);
		fclose($fp);
		unset($content, $filename, $fp);
	}

	/**
	 * Проверка кэш-файлов
	 *
	 * @param	string	$filename		Имя проверяемого кэш-файла
	 * @param	int		$expiry			Максимальный «возраст» файла в секундах
	 * @return	mixed					Содержимое кэша или false
	 */
	public function readCache($filename, $expiry)
	{
		if (file_exists(ABSPATH . 'templates/' . TPL_NAME . '/' . LANG . '/cache/' . $filename))
		{
			if ((time() - $expiry) > filemtime(ABSPATH . 'templates/' . TPL_NAME . '/' . LANG . '/cache/' . $filename))
			{
				unset($filename, $expiry);
				return false;
			}
			$cache = file(ABSPATH . 'templates/' . TPL_NAME . '/' . LANG . '/cache/' . $filename);
			unset($filename, $expiry);
			return implode('', $cache);
		}
		unset($filename, $expiry);
		return false;
	}

	/**
	 * UID()
	 * Функция генерурует уникальный UIN
	 *
	 * @return	string
	 */
	public function UIN()
	{
		srand((double) microtime( ) * 1000000);
		return uniqid(rand(), true);
	}
	
	/**
	 * Обратимое шифрование методом "Двойного квадрата" (Reversible crypting of "Double square" method)
	 * @param  String $input   Строка с исходным текстом
	 * @param  bool   $decrypt Флаг для дешифрования
	 * @return String          Строка с результатом Шифрования|Дешифрования
	 * @author runcore
	 */
	public function dsCrypt($input, $decrypt=false) 
	{
		$o = $s1 = $s2 = array(); // Arrays for: Output, Square1, Square2
		// формируем базовый массив с набором символов
		$basea = array('?','(','@',';','$','#',"]","&",'*');  // base symbol set
		$basea = array_merge($basea, range('a','z'), range('A','Z'), range(0,9) );
		$basea = array_merge($basea, array('!',')','_','+','|','%','/','[','.',' ') );
		$dimension=9; // of squares
		for($i=0;$i<$dimension;$i++) { // create Squares
			for($j=0;$j<$dimension;$j++) {
				$s1[$i][$j] = $basea[$i*$dimension+$j];
				$s2[$i][$j] = str_rot13($basea[($dimension*$dimension-1) - ($i*$dimension+$j)]);
			}
		}
		unset($basea);
		$m = floor(strlen($input)/2)*2; // !strlen%2
		$symbl = $m==strlen($input) ? '':$input[strlen($input)-1]; // last symbol (unpaired)
		$al = array();
		// crypt/uncrypt pairs of symbols
		for ($ii=0; $ii<$m; $ii+=2) {
			$symb1 = $symbn1 = strval($input[$ii]);
			$symb2 = $symbn2 = strval($input[$ii+1]);
			$a1 = $a2 = array();
			for($i=0;$i<$dimension;$i++) { // search symbols in Squares
				for($j=0;$j<$dimension;$j++) {
					if ($decrypt) {
						if ($symb1===strval($s2[$i][$j]) ) $a1=array($i,$j);
						if ($symb2===strval($s1[$i][$j]) ) $a2=array($i,$j);
						if (!empty($symbl) && $symbl===strval($s2[$i][$j])) $al=array($i,$j);
					}
					else {
						if ($symb1===strval($s1[$i][$j]) ) $a1=array($i,$j);
						if ($symb2===strval($s2[$i][$j]) ) $a2=array($i,$j);
						if (!empty($symbl) && $symbl===strval($s1[$i][$j])) $al=array($i,$j);
					}
				}
			}
			if (sizeof($a1) && sizeof($a2)) {
				$symbn1 = $decrypt ? $s1[$a1[0]][$a2[1]] : $s2[$a1[0]][$a2[1]];
				$symbn2 = $decrypt ? $s2[$a2[0]][$a1[1]] : $s1[$a2[0]][$a1[1]];
			}
			$o[] = $symbn1.$symbn2;
		}
		if (!empty($symbl) && sizeof($al)) // last symbol
			$o[] = $decrypt ? $s1[$al[1]][$al[0]] : $s2[$al[1]][$al[0]];
		return implode('',$o);
	}
	
	/**
	 * 
	 * @param type $sec
	 * @return type
	 */
	function f_time($sec) 
	{
		$a = array(
			86400 => 'д.', // количество секунд в сутках
			3600  => 'ч.', // количество секунд в часе
			60    => 'м.', // количество секунд в минуте
			1     => 'с.' // количество секунд в секунде
		);
		$out = '';
		foreach ($a as $k => $v) 
		{
			$tmp = floor($sec/$k);
			$out .= ($tmp?$tmp.$v.' ':'');
			$sec -= $tmp*$k;
		}
		unset($a, $k, $v, $sec, $tmp);
		return $out;
	}
	
	/**
	 * Проверяет правильность даты
	 * 
	 * @param type $Str
	 * @return type
	 */
	public function IsDate($Str)
	{
		$Stamp = strtotime($Str);
		$Month = date('m', $Stamp);
		$Day   = date('d', $Stamp);
		$Year  = date('Y', $Stamp);
		
		unset($Str, $Stamp);
		return checkdate($Month, $Day, $Year);
	}
	
	/**
	 * Проверяет правильность даты
	 * 
	 * @param type $dateTime
	 * @return boolean
	 */
	public function isValidDateTime($dateTime)
	{
		$matches = array();
		$dateTime=(string)$dateTime;
		if (preg_match("/^(\d{4})-(\d{2})-(\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $dateTime, &$matches)) 
		{
			if (checkdate($matches[2], $matches[3], $matches[1])) 
			{
				return true;
			}
		}
		return false;
	}
	
	/**
	 * 
	 * @param type $b
	 * @param type $a
	 * @return type
	 */
	public function diffdate($b,$a) 
	{
		if($a<$b) list($a,$b)=array($b,$a);
		$ca = array(); 
		$ka = array('years','months','days','hours','minutes','seconds'); 
		$da = array(0,12,date('t',$a),23,59,59);
		$aa = explode(' ',date('Y n j G i s',$a)); 
		$ba = explode(' ',date('Y n j G i s',$b)); 
		foreach($aa as $k=>$v) 
			if(($r=$v-$ba[$k])<0) 
			{
				$ca[$ka[$k]] = $da[$k]+$r;
				$ca[$ka[$k-1]]--; 
			}
			else
				$ca[$ka[$k]] = $r;
		foreach($ca as $k=>$v)
			if($v==0) unset($ca[$k]);
		return $ca; 
	}
	
	/**
	 * 
	 * @param type $filename
	 * @return type
	 */
	public function file_extension($filename)
	{
		return strtolower(end(explode('.', $filename)));
	}
	
	/**
	 *
	 * @param	string	$txt 
	 */
	public function addToLog($txt)
	{
		$filename = ABSPATH . 'log/log.txt';
		
		// Убедимся в том, что файл существует и доступен для записи
		if (is_writable($filename)) 
		{
			if (!$handle = fopen($filename, 'a')) 
			{
				//echo "Cannot open file ($filename)";
				exit;
			}

			// Write $somecontent to our opened file.
			if (fwrite($handle, date('d.m.Y H:i:s') . "\t" . $txt . "\n") === false)
			{
				//echo "Cannot write to file ($filename)";
				exit;
			}

			//echo "Success, wrote ($somecontent) to file ($filename)";

			fclose($handle);
		}
	}
}
?>